package com.example.demo.security; // 您可以放在一个合适的包下，例如 util 或 security

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct; // 引入 PostConstruct
import java.security.Key;
import java.util.Base64; // 用于打印密钥（仅调试，生产环境不推荐）
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtUtil {

    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);

    // 不再从配置文件读取 secretKeyString
    // @Value("${jwt.secret}")
    // private String secretKeyString;

    @Value("${jwt.expiration.ms}")
    private long jwtExpirationInMs;

    private Key signingKey; // 用于存储生成的密钥

    /**
     * 在Bean初始化后执行，用于生成密钥。
     * 这种方式使得密钥在应用单次运行期间是固定的。
     */
    @PostConstruct
    public void init() {
        // 使用 Keys.secretKeyFor 生成一个安全的密钥，适用于指定的签名算法
        // HS256 算法需要至少 256 位的密钥
        this.signingKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        log.info("JWT signing key generated successfully for HS256 algorithm.");

        // !!! 警告：仅用于调试目的，不要在生产环境中打印密钥 !!!
        // 如果需要查看生成的密钥（例如，用于手动验证或与其他系统集成时的临时调试）
        // log.debug("Generated JWT Secret Key (Base64): {}", Base64.getEncoder().encodeToString(this.signingKey.getEncoded()));
        // !!! 生产环境中务必移除或注释掉上面这行日志 !!!
    }

    private Key getSigningKey() {
        // 直接返回在 init() 方法中生成的密钥
        if (this.signingKey == null) {
            // 理论上 PostConstruct 应该已经执行，但作为防御性编程可以再次调用或抛出异常
            log.error("Signing key has not been initialized!");
            throw new IllegalStateException("JWT Signing Key has not been initialized. Check PostConstruct method.");
        }
        return this.signingKey;
    }

    // 从 JWT 中提取用户名 (subject)
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    // 从 JWT 中提取过期日期
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }

    // 从 JWT 中提取指定的 Claim
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    // 从 JWT 中提取所有的 Claims
    private Claims extractAllClaims(String token) {
        return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
    }

    // 检查 JWT 是否已过期
    private Boolean isTokenExpired(String token) {
        try {
            return extractExpiration(token).before(new Date());
        } catch (Exception e) {
            // 如果在提取过期时间时发生错误（例如token格式错误），也视为过期或无效
            log.warn("Could not extract expiration from token, considering it expired or invalid.", e);
            return true;
        }
    }

    // 为指定用户生成 JWT
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        // 您可以在这里添加额外的 claims，例如用户角色、权限等
        // claims.put("roles", userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));
        return createToken(claims, userDetails.getUsername());
    }

    // 为指定用户名生成 JWT (如果不想直接依赖 UserDetails)
    public String generateToken(String username) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, username);
    }


    // 创建 JWT
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject) // 通常是用户名
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + jwtExpirationInMs))
                .signWith(getSigningKey(), SignatureAlgorithm.HS256) // 确保算法一致
                .compact();
    }

    // 验证 JWT 是否有效 (用户名匹配且未过期)
    public Boolean validateToken(String token, UserDetails userDetails) {
        try {
            final String username = extractUsername(token);
            return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
        } catch (Exception e) {
            log.warn("Token validation failed for user {}: {}", userDetails != null ? userDetails.getUsername() : "unknown", e.getMessage());
            return false;
        }
    }

    // 验证 JWT 是否有效 (仅检查是否可解析且未过期，不对比用户名)
    public Boolean validateToken(String token) {
        try {
            // parseClaimsJws 会验证签名和过期时间（如果已过期会抛出 ExpiredJwtException）
            Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
            // 如果上面没有抛出异常，说明签名有效且未过期（或过期异常已被捕获）
            // 严格来说，如果上面解析成功，isTokenExpired 应该返回 false，除非时间窗口极小
            // 但为了明确，再检查一次
            return !isTokenExpired(token);
        } catch (io.jsonwebtoken.ExpiredJwtException eje) {
            log.warn("JWT token is expired: {}", eje.getMessage());
            return false;
        } catch (io.jsonwebtoken.JwtException | IllegalArgumentException e) {
            // 包括 SignatureException, MalformedJwtException, UnsupportedJwtException, IllegalArgumentException 等
            log.warn("JWT token validation error: {}", e.getMessage());
            return false;
        }
    }
}
